# game_rules.py
import copy
import random


def place_stone(board, current_player, row, col, board_size, position_history):
    """在指定位置放置棋子（返回是否成功、更新后的棋盘、捕获数量和是否成功标志）"""
    if not (0 <= row < board_size and 0 <= col < board_size and not board[row][col]):
        return board, {'BLACK': 0, 'WHITE': 0}, False

    # 检查是否是禁入点
    if is_suicide(board, current_player, row, col, board_size) or is_ko(board, current_player, row, col,
                                                                        position_history, board_size):
        return board, {'BLACK': 0, 'WHITE': 0}, False

    # 保存当前状态到历史记录
    new_board = copy.deepcopy(board)
    new_board[row][col] = current_player

    # 检查并执行提子
    new_board, captures = check_captures(new_board, current_player, row, col, board_size)

    # 如果没有提子且是自杀点，回退落子
    if not any(captures.values()) and is_suicide(new_board, current_player, row, col, board_size):
        new_board[row][col] = None
        return board, {'BLACK': 0, 'WHITE': 0}, False

    return new_board, captures, True


def is_suicide(board, current_player, row, col, board_size):
    """检查落子是否是自杀（禁入点）"""
    # 模拟落子
    temp_board = copy.deepcopy(board)
    temp_board[row][col] = current_player

    # 检查新落子的棋子是否有气
    if has_liberty(temp_board, row, col, current_player, board_size):
        return False

    # 检查是否提走对方棋子
    opponent = 'WHITE' if current_player == 'BLACK' else 'BLACK'
    directions = [(0, 1), (1, 0), (0, -1), (-1, 0)]

    for dr, dc in directions:
        r, c = row + dr, col + dc
        if 0 <= r < board_size and 0 <= c < board_size:
            if temp_board[r][c] == opponent:
                if not has_liberty(temp_board, r, c, opponent, board_size):
                    return False
    return True


def is_ko(board, current_player, row, col, position_history, board_size):
    """检查是否是劫（全局禁入点）"""
    if not position_history:
        return False

    # 模拟落子
    temp_board = copy.deepcopy(board)
    temp_board[row][col] = current_player

    # 提掉被包围的棋子
    opponent = 'WHITE' if current_player == 'BLACK' else 'BLACK'
    directions = [(0, 1), (1, 0), (0, -1), (-1, 0)]
    captured_stones = []

    for dr, dc in directions:
        r, c = row + dr, col + dc
        if 0 <= r < board_size and 0 <= c < board_size:
            if temp_board[r][c] == opponent:
                if not has_liberty(temp_board, r, c, opponent, board_size):
                    # 记录被提的棋子
                    group = get_group(temp_board, r, c, opponent, board_size)
                    captured_stones.extend(group)

    # 移除被提的棋子
    for r, c in captured_stones:
        temp_board[r][c] = None

    # 检查是否形成劫
    for past_state in position_history:
        match = True
        for r in range(board_size):
            for c in range(board_size):
                if temp_board[r][c] != past_state[r][c]:
                    match = False
                    break
            if not match:
                break
        if match:
            return True
    return False


def check_captures(board, current_player, row, col, board_size):
    """检查并执行提子 - 修复边缘提子问题"""
    opponent = 'WHITE' if current_player == 'BLACK' else 'BLACK'
    groups_to_remove = []  # 记录需要移除的所有棋块
    visited_groups = set()  # 记录已处理过的棋块
    captures = {'BLACK': 0, 'WHITE': 0}

    # 检查所有相邻位置
    for dr, dc in [(0, 1), (1, 0), (0, -1), (-1, 0)]:
        r, c = row + dr, col + dc

        if not (0 <= r < board_size and 0 <= c < board_size):
            continue

        if board[r][c] != opponent:
            continue

        # 检查是否已经处理过该棋块
        if (r, c) in visited_groups:
            continue

        # 检查该棋块是否有气
        if not has_liberty(board, r, c, opponent, board_size):
            # 获取整个棋块并添加到移除列表
            group = get_group(board, r, c, opponent, board_size)
            groups_to_remove.append(group)

            # 标记该棋块所有棋子为已处理
            for pos in group:
                visited_groups.add(pos)

    # 一次性移除所有无气棋块
    new_board = copy.deepcopy(board)
    for group in groups_to_remove:
        for r, c in group:
            new_board[r][c] = None
            captures['BLACK' if opponent == 'WHITE' else 'WHITE'] += 1

    return new_board, captures


def has_liberty(board, row, col, color, board_size, visited=None):
    """检查棋子是否有气"""
    if visited is None:
        visited = set()

    if (row, col) in visited:
        return False
    visited.add((row, col))

    directions = [(0, 1), (1, 0), (0, -1), (-1, 0)]
    for dr, dc in directions:
        r, c = row + dr, col + dc
        if 0 <= r < board_size and 0 <= c < board_size:
            if board[r][c] is None:
                return True
            if board[r][c] == color:
                if has_liberty(board, r, c, color, board_size, visited):
                    return True
    return False


def get_group(board, row, col, color, board_size, visited=None):
    """获取整块棋子"""
    if visited is None:
        visited = set()

    if (row, col) in visited:
        return []
    visited.add((row, col))

    group = [(row, col)]
    directions = [(0, 1), (1, 0), (0, -1), (-1, 0)]

    for dr, dc in directions:
        r, c = row + dr, col + dc
        if 0 <= r < board_size and 0 <= c < board_size:
            if board[r][c] == color:
                group.extend(get_group(board, r, c, color, board_size, visited))
    return group


def mark_territory(board, board_size):
    """标记领地归属"""
    territory = [[None] * board_size for _ in range(board_size)]
    visited = set()

    # 标记所有空点的领地归属
    for r in range(board_size):
        for c in range(board_size):
            if board[r][c] is None and (r, c) not in visited:
                # 检查该空点的领地归属
                territory_color, territory_group = get_territory(board, r, c, board_size)
                if territory_color:
                    # 标记整块领地
                    for tr, tc in territory_group:
                        territory[tr][tc] = territory_color
                        visited.add((tr, tc))

    # 标记已有棋子的领地
    for r in range(board_size):
        for c in range(board_size):
            if board[r][c]:
                territory[r][c] = board[r][c]

    return territory


def get_territory(board, r, c, board_size):
    """确定一块空地的领地归属"""
    stack = [(r, c)]
    visited = set()
    territory = set()
    border_colors = set()

    while stack:
        row, col = stack.pop()
        if (row, col) in visited:
            continue

        visited.add((row, col))
        territory.add((row, col))

        # 检查四个方向
        for dr, dc in [(0, 1), (1, 0), (0, -1), (-1, 0)]:
            nr, nc = row + dr, col + dc
            if 0 <= nr < board_size and 0 <= nc < board_size:
                if board[nr][nc] is None:
                    if (nr, nc) not in visited:
                        stack.append((nr, nc))
                else:
                    border_colors.add(board[nr][nc])

    # 如果整块领地被同一方包围
    if len(border_colors) == 1:
        return (next(iter(border_colors)), territory)

    return (None, territory)


def calculate_score(board, territory, komi=7.5, captures=None):
    """按照中国规则计算得分并判定胜负"""
    # 如果没有提供captures参数，初始化为空字典
    if captures is None:
        captures = {'BLACK': 0, 'WHITE': 0}

    # 统计棋盘上的黑子和白子数量
    black_stones = 0
    white_stones = 0

    # 统计领地（空交叉点归属）
    black_territory = 0
    white_territory = 0

    # 计算黑棋和白棋在棋盘上的棋子数
    board_size = len(board)
    for r in range(board_size):
        for c in range(board_size):
            if board[r][c] == 'BLACK':
                black_stones += 1
            elif board[r][c] == 'WHITE':
                white_stones += 1

    # 计算双方的领地（空交叉点归属）
    for r in range(len(territory)):
        for c in range(len(territory[r])):
            if board[r][c] is None:  # 空交叉点
                if territory[r][c] == 'BLACK':
                    black_territory += 1
                elif territory[r][c] == 'WHITE':
                    white_territory += 1

    # 根据中国规则计算最终得分
    # 黑方得分 = 黑子数量 + 黑方领地 + 提子数
    # 白方得分 = 白子数量 + 白方领地 + 提子数 + 贴目
    black_score = black_stones + black_territory + captures.get('BLACK', 0)
    white_score = white_stones + white_territory + captures.get('WHITE', 0) + komi

    # 比较得分判定胜负
    if black_score > white_score:
        winner = '黑方胜'
    elif white_score > black_score:
        winner = '白方胜'
    else:
        winner = '平局'

    return black_score, white_score, winner